#!/usr/bin/ruby

require 'yaml'
require 'optparse'
require 'permissions'
require 'evolution'
require 'calendar-jabber-bot'
require 'calendar-jabber-server'

CONFIG_FILE=ENV["HOME"]+"/.edsbotrc"
PID_FILE=ENV["HOME"]+"/.edsbotpid"
CLIENT_JID = "user@server"
CLIENT_PWD = "passwd"


class Driver

	@conf = nil
	ALLOWED_OPERATIONS=[:read, :write]
	ALLOWED_COMMANDS=[:start, :reconfigure, :stop]
	@@allowed_ops = "[" + ALLOWED_OPERATIONS.join("|") + "]"
	def get_pass()
		begin
			system "stty -echo"
			print "Password: "
			passwd = $stdin.gets.chomp
			print "\n"
		ensure
			system "stty echo"
		end
		return passwd
	end


	def init_config()
		
		@conf = Hash.new
		@conf['auth'] = {'jid' => CLIENT_JID, 'passwd'=> CLIENT_PWD, 'server' => 'jabber.org'}
		@conf['permissions'] = Authorizer::Permissions.new
		puts "Error opening #{CONFIG_FILE}, trying to create one"
		save_config()
	end

	def get_config()
		@conf = YAML.load_file(CONFIG_FILE)          
	end

	def save_config()
		File.open( CONFIG_FILE, 'w' ) do |out|
			YAML.dump(@conf, out )
		end
	end

	def cmd_allow(usr, cal, op)
		@conf['permissions'].allow(usr,cal,[op.to_sym])
	end

	def cmd_deny(usr, cal, op)
		@conf['permissions'].deny(usr,cal,[op.to_sym])
	end

	def cmd_list_shares()
		puts "------------------------------"
		puts "Calendar shares and user acess"
		puts "------------------------------"
		@conf['permissions'].each {
			|usr, cal, op|
			puts "'#{usr}' has [#{op.join("|")}] access to '#{cal}'"
		}
		puts
	end
	
	
	def cmd_list_calendars()
		puts "----------------------------------------"
		puts "Calendars available in this system (uid)"
		puts "----------------------------------------"
		Evolution::get_esource_groups.each {|grp|
			grp.each{|src| 
				puts "#{src.name} (#{src.uid})"
			}
		}
		puts
	end
	
	def calendar_exists(cal)
		return Evolution::get_esource_groups.find  {|grp|
				grp.find{|src|	src.uid==cal
			}
		} 
	end

	def check_access_params(list)
		raise "Wrong number of arguments" unless list.size==3
		raise "Unsupported access on calendar. Allowed accesses are #{@@allowed_ops}." unless ALLOWED_OPERATIONS.include?(list[2].to_sym)
		raise "Calendar does not exists" unless calendar_exists(list[1])	
	end


	def parse_opts(args)
		should_run=true
		opts = OptionParser.new do |opts|
			opts.banner = "Usage: calendar-share.rb [start|reconfigure|stop] [options]"
			opts.separator ""
			opts.separator "Options: "

			opts.on("-a", "--allow JID,UID,OP", Array, "Allow user JID #{@@allowed_ops} access to calendar UID.") do |list|
				check_access_params(list)
				cmd_allow(*list)
				should_run=false				
			end
			opts.on("-d", "--deny JID,UID,OP", Array, "Deny user JID #{@@allowed_ops} access to calendar UID.") do |list|
				check_access_params(list)
				cmd_deny(*list)
				should_run=false				
			end
			
			opts.on("-l", "--list-shares", "List calendar shares and user acess") do 
				cmd_list_shares()
				should_run=false				
			end

			opts.on("-L", "--list-calendars", "List available calendars in e-d-s") do 
				cmd_list_calendars()
				should_run=false				
			end
			
			opts.on("-u", "--user JID", "Use jid for connecting to the jabber server") do |jid| 
				@conf['auth']['jid']= jid 
				should_run  = false
			end
						
			opts.on("-p", "--password [PASSWD]", "Use password for connecting to the jabber server") do |passwd| 
				@conf['auth']['passwd']= passwd || get_pass 
				should_run  = false
			end

			opts.on("-s", "--server SERVER", "Connect to this jabber server") do |srv| 
				@conf['auth']['server'] = srv				
				should_run  = false
			end

			opts.parse!(args)		  
		end
		return should_run, opts
	end

	def get_pid()
		apid=nil
		File.open(PID_FILE) do |file|
			apid=file.read()
		end
		return apid.to_i
	end

	def run()					
		init_config() unless File.exists?(CONFIG_FILE) 
		get_config()		
		should_run,opts = parse_opts(ARGV)
		save_config()
		return unless should_run
		if ARGV.size == 0 then
			puts opts.banner
			return
		end
		case ARGV[0].to_sym
			when :start				
				raise "#{$0} already running" if File.exists?(PID_FILE)
				File.open(PID_FILE, "w") do |file|
					file.write(Process.pid.to_s)
				end
				begin

					pid_http = fork do
						srv=CalendarHTTPServer.new(CONFIG_FILE)	
						srv.run()
						Process.exit	
					end

					#start a child process to serve 
					#calendars via xml-rpc

					pid_xmpp = fork do		
						srv=CalendarJabberBot.new(CONFIG_FILE)	
						srv.run()
						Process.exit				
					end
					
					trap('HUP') do
						#signal HUP on child processes
						save_config()
						Process.kill('HUP', pid_xmpp)
						Process.kill('HUP', pid_http)
					end

					trap('INT') do
						#signal INT on child processes
						Process.kill('INT', pid_xmpp)
						Process.kill('INT', pid_http)
					end

					

					#end running ui
					Process.wait(pid_http)
					Process.wait(pid_xmpp)
				ensure
					File.delete(PID_FILE)			
				end

			when :configure, :reconfigure then 
				raise "#{$0} not running" unless File.exists?(PID_FILE)
				Process.kill('HUP', get_pid)
			when :stop then	
				raise "#{$0} not running" unless File.exists?(PID_FILE)
				Process.kill('INT', get_pid)
		end
		
	end
end

Driver.new.run()
